package function.client;

import function.Result;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.stereotype.Component;

import java.util.Objects;

/**
 * 用户相关远程服务调用client
 *
 * @author G_Y
 * @version 1.0.0, 2022/3/29 15:33
 **/
@Slf4j
@Component
public class UserClient2 extends AbstractClient2 {

    @Reference(version = "1.0.0", check = false, retries = 0)
    private UserFacade userFacade;

    private static final String QUERY_USER_METHOD_NAME = "function.client.UserFacade#queryUserInfo";

    private static final String REWARD_POINTS_METHOD_NAME = "function.client.UserFacade#rewardPoints";

    @Override
    String getLogErrorCode() {
        return ClientLogErrorCode.RPC_USER_ERROR_CODE;
    }

    /**
     * 查询用户信息
     *
     * @author G_Y, 2022/3/29 16:04
     **/
    public Result<RespUserInfo> queryUserInfo(QueryUserRequest request) {

        // 实体转换
        QueryUserInfoDTO reqDto = this.exchange(request);

        RpcResult<UserInfoDTO> rpcResult = super.invoke(reqDto, userFacade::queryUserInfo, this::queryUserInfoResultCheck, QUERY_USER_METHOD_NAME);

        // 不符合预期，invoke方法会统一返回null
        if (Objects.isNull(rpcResult)) {
            return Result.failed();
        }

        // 成功，实体转换
        RespUserInfo respUserInfo = this.exchange(rpcResult.getData());

        return Result.success(respUserInfo);

    }

    /**
     * 查询用户信息 响应结果校验
     *
     * @author G_Y, 2022/3/30 14:28
     **/
    private boolean queryUserInfoResultCheck(QueryUserInfoDTO req, RpcResult<UserInfoDTO> result) {

        // 这里的result如果不是RpcResult类型，需要单独判断业务调用是否成功

        if (Objects.isNull(result.getData())) {
            // 这里可以补充具体不符合预期的原因日志，不需要再打请求参数，响应结果，可以根据日志上下文定位
            log.error(LogUtils.errorLog("{} RPC调用，响应的Result中data为空，不符合约定。", this.getLogErrorCode()), QUERY_USER_METHOD_NAME);
            return false;
        }

        if (StringUtils.isEmpty(result.getData().getPhone())) {
            // 这里可以补充具体不符合预期的原因日志
            log.error(LogUtils.errorLog("{} RPC调用，响应的电话号码为空，不符合约定。", this.getLogErrorCode()), QUERY_USER_METHOD_NAME);
            return false;
        }

        // 符合期望
        return true;
    }

    /**
     * 奖励用户积分
     *
     * @author G_Y, 2022/3/29 16:05
     **/
    public Result<Void> rewardPoints(rewardPointsRequest request) {

        // 实体转换
        rewardPointsRequestDTO reqDto = this.exchange(request);

        RpcResult<Boolean> rpcResult = super.invoke(reqDto, userFacade::rewardPoints, this::rewardPointsResultCheck, REWARD_POINTS_METHOD_NAME);

        // 不符合预期，invoke方法会统一返回null
        if (Objects.isNull(rpcResult)) {
            return Result.failed();
        }

        return Result.success();

    }

    /**
     * 奖励用户积分 调用结果校验
     *
     * @author G_Y, 2022/3/30 14:28
     **/
    private boolean rewardPointsResultCheck(rewardPointsRequestDTO req, RpcResult<Boolean> result) {

        // 这里的result如果不是RpcResult类型，需要单独判断业务调用是否成功

        if (Objects.isNull(result.getData())) {
            // 这里可以补充具体不符合预期的原因日志，不需要再打请求参数，响应结果，可以根据日志上下文定位
            log.error(LogUtils.errorLog("{} RPC调用，响应的Result中data为空，不符合约定。", this.getLogErrorCode()), REWARD_POINTS_METHOD_NAME);
            return false;
        }

        if (!result.getData()) {
            // 这里可以补充具体不符合预期的原因日志
            log.error(LogUtils.errorLog("{} RPC调用，响应的data为false，不符合约定。", this.getLogErrorCode()), REWARD_POINTS_METHOD_NAME);
            return false;
        }

        // 符合期望
        return true;

    }


    private QueryUserInfoDTO exchange(QueryUserRequest request) {
        return null;
    }

    private RespUserInfo exchange(UserInfoDTO request) {
        return null;
    }

    private rewardPointsRequestDTO exchange(rewardPointsRequest request) {
        return null;
    }

    // other methods ...

}
